package com.acme.bankapp.service.bank;

import com.acme.bankapp.domain.bank.Account;
import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.domain.bank.Client;
import com.acme.bankapp.domain.bank.exceptions.ClientExistsException;

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class BankService {
    public enum PrintType {BALANCE, MAX_WITHDRAW}

    public static Client addClient(Bank bank, Client client) throws ClientExistsException {
        return bank.addClient(client);
    }

    public static void modifyBank(Bank bank) {
        for (Client client : bank.getClients()) {
            for (Account account : client.getAccounts()) {
                account.deposit(1);
            }
        }

        if (bank.getBankPath() != null) {
            try {
                saveBank(bank, bank.getBankPath());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static String print(Bank bank, PrintType type) {
        StringBuilder clients = new StringBuilder();
        for (Client client : bank.getClients()) {
            clients.append("Client ").append(client).append('\n');
            for (Account account : client.getAccounts()) {
                switch (type) {
                    case BALANCE:
                        clients.append("balance:").append(account.getBalance()).append('\n');
                        break;
                    case MAX_WITHDRAW:
                        clients.append("max withdraw:").append(account.maximumAmountToWithdraw()).append('\n');
                        break;
                }
            }
        }
        return clients.toString();
    }

    public static void loadClients(Bank bank, String arg) throws IOException, ClientExistsException {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(arg))) {
            Scanner scanner = new Scanner(bis);
            while (scanner.hasNextLine()) {
                String str = scanner.nextLine();
                loadClientsFromString(bank, str);
            }
        }
    }

    public static void loadClientsFromString(Bank bank, String str) throws IOException, ClientExistsException {
        String[] fields = str.split(";");
        int overdraft = 0, balance = 0;
        String name = null;
        Client.Gender gender = Client.Gender.MALE;
        for (String field : fields) {
            String[] items = field.split("=");
            if (items.length != 2) {
                System.out.println("Error format!");
            }
            switch (items[0]) {
                case "balance":
                    balance = Integer.parseInt(items[1]);
                    break;
                case "overdraft":
                    overdraft = Integer.parseInt(items[1]);
                    break;
                case "name":
                    name = items[1];
                    break;
                case "gender":
                    gender = (items[1].equals("m")) ? Client.Gender.MALE : Client.Gender.FEMALE;
                    break;
            }
        }

        bank.addClient(ClientFactory.createClient(balance, overdraft, gender, name));

        if (bank.getBankPath() != null) {
            saveBank(bank, bank.getBankPath());
        }
    }

    public static void saveBank(Bank bank, String path) throws IOException {
        bank.setBankPath(path);
        try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(path)))) {
            oos.writeObject(bank);
        }
    }

    public static Bank[] readBanks(String path) throws IOException {
        try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(path)))) {
            List<Bank> banks = new LinkedList<>();
            Bank bank;
            try {
                while ((bank = (Bank) ois.readObject()) != null) {
                    bank.setBankPath(path);
                    bank.initListeners();
                    banks.add(bank);
                }
            } catch (ClassNotFoundException e) {
                System.out.println("Unknown class");
            } catch (EOFException e) {
                //supressing exception.
            }
            return banks.toArray(new Bank[banks.size()]);
        }
    }

    public static void enableEmailToBank(Bank bank) {
        EmailService emailService = new EmailService();
        emailService.start();
        bank.addListener(bank.new EmailClientListener(emailService));
    }

    public static void stopBank(Bank bank) {
        bank.stopListeners();
    }
}

